﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;

namespace FifaGamer
{
    /// <summary>
    /// Summary description for Login
    /// </summary>
    public static class Authentication
    {
        const string AUTH_USERNAME = "AUTH_USERNAME";
        const string AUTH_COOKIE = "AUTH_COOKIE";
        const string AUTH_COOKIE_USERNAME = "AUTH_COOKIE_USERNAME";
        const string AUTH_COOKIE_PASSWORD = "AUTH_COOKIE_PASS";

        /// <summary>
        /// Logs in the user
        /// </summary>
        /// <param name="email"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public static KeyValuePair<bool, string> Login(string email, string password)
        {
            //verify the passed details
            if (!string.IsNullOrWhiteSpace(email) && !string.IsNullOrWhiteSpace(password))
            {
                //verify the logged in user
                if (Account.Verify_Account(email, password))
                {
                    //store/update user sessions + httpcontext cookies
                    Account account = Account.Get_Account(email);
                    Add_AccountToSession(account);
                    Add_AccountToCookie(account);

                    return new KeyValuePair<bool, string>(true, "Logged in successfully");
                }            
            }
            return new KeyValuePair<bool, string>(false, "The username or password is invalid");
        }

        /// <summary>
        /// Logs out a user
        /// </summary>
        /// <returns></returns>
        public static bool Logout()
        {
            Remove_AccountFromCookie();
            Remove_AccountFromSession();
            return true;
        }

        /// <summary>
        /// Adds an account to the current http context session
        /// </summary>
        /// <param name="account"></param>
        /// <returns></returns>
        private static bool Add_AccountToSession(Account account)
        {
            HttpContext.Current.Session.Remove(AUTH_USERNAME);
            HttpContext.Current.Session[AUTH_USERNAME] = account;
            return true;
        }

        /// <summary>
        /// Adds an account details to the user's cookie container
        /// </summary>
        /// <param name="account"></param>
        /// <returns></returns>
        private static bool Add_AccountToCookie(Account account)
        {
            HttpContext.Current.Response.Cookies[AUTH_COOKIE][AUTH_COOKIE_USERNAME] = account.Username;
            HttpContext.Current.Response.Cookies[AUTH_COOKIE][AUTH_COOKIE_PASSWORD] = account.PasswordHash;
            HttpContext.Current.Response.Cookies[AUTH_COOKIE].Expires = DateTime.Now.AddDays(7);
            return true;
        }

        /// <summary>
        /// Removes a user form the session
        /// </summary>
        /// <returns></returns>
        private static bool Remove_AccountFromSession()
        {
            HttpContext.Current.Session.Remove(AUTH_USERNAME);
            return true;
        }

        /// <summary>
        /// Remove the authentication cookie
        /// </summary>
        /// <returns></returns>
        private static bool Remove_AccountFromCookie()
        {
            if (HttpContext.Current.Response.Cookies[AUTH_COOKIE] != null)
            {
                HttpCookie cookie = new HttpCookie(AUTH_COOKIE);
                cookie.Expires = DateTime.Now.AddDays(-1);
                HttpContext.Current.Response.Cookies.Add(cookie);
            }
            return true;
        }



        /// <summary>
        /// Returns the hash to the party
        /// </summary>
        /// <param name="password"></param>
        /// <returns></returns>
        public static string EncryptPassword(string password)
        {
            var bytes = Encoding.UTF8.GetBytes(password);
            return Convert.ToBase64String(bytes);
        }

        /// <summary>
        /// Decrypts a password
        /// </summary>
        /// <param name="encryptedPassword"></param>
        /// <returns></returns>
        public static string DecryptPassword(string encryptedPassword)
        {
            var bytes = Convert.FromBase64String(encryptedPassword);
            return Encoding.UTF8.GetString(bytes);
        }

        private static readonly Random _rng = new Random();
        private const string _chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0987612345";
        public static string GeneratePassword(int size)
        {
            char[] buffer = new char[size];

            for (int i = 0; i < size; i++)
            {
                buffer[i] = _chars[_rng.Next(_chars.Length)];
            }
            return new string(buffer);
        }

        public static Account Get_LoggedInUser()
        {
            Account account = null;

            //dig the sessions first... 
            var sessionAccount = HttpContext.Current.Session[AUTH_USERNAME];
            if (sessionAccount != null && sessionAccount is Account)
            {
                //get the account, and restore it in cookie
                account = sessionAccount as Account;                
                Add_AccountToCookie(account);
                return account;                
            }

            //now try to dig the login from the cookie            
            var cookieAccount = HttpContext.Current.Request.Cookies[AUTH_COOKIE];
            if (cookieAccount != null && !string.IsNullOrWhiteSpace(cookieAccount[AUTH_COOKIE_USERNAME]) && !string.IsNullOrWhiteSpace(cookieAccount[AUTH_COOKIE_PASSWORD]))
            {
                var cookieUsername = cookieAccount[AUTH_COOKIE_USERNAME];
                var cookiePassword = cookieAccount[AUTH_COOKIE_PASSWORD];

                if (Account.Verify_AccountHash(cookieUsername, cookiePassword))
                {
                    account = Account.Get_Account(cookieUsername);
                    Add_AccountToSession(account);
                    Add_AccountToCookie(account);
                    return account;
                }
                else
                {
                    Remove_AccountFromSession();
                    Remove_AccountFromCookie();
                    return account;
                }
            }            

            return account;
        }
    }
}